package com.xxxx.server.config.security.component;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 * // * 权限控制
 * // * 判断用户角色
 * // *
 * // * @author: STFU
 * // * @create: 2021-03-27
 * //
 **/

// 分析当前用户是否具有需要的角色

@Component
public class CustomUrlDecisionManager implements AccessDecisionManager {
    /**
     *
     * @param authentication 在pojo.admin.getAuthorities()里被设置
     * @param object
     * @param configAttributes 由CustomerFilter里SecurityConfig.createList()被设置
     * @throws AccessDeniedException
     * @throws InsufficientAuthenticationException
     */
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute>
            configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        //这个configAttributes就是CustomFilterInvocationSecurityMetadataSource.java里面根据请求的Url获取到的所需对象
        for (ConfigAttribute configAttribute : configAttributes) {
            //  当前url所需角色
            String needRole = configAttribute.getAttribute();
            //  判断角色是否登录即可访问的角色， 此角色在CustomFilter中设置
            //  这里对应的是没有匹配到角色的Url，默认是需要登录后才能访问
            //  如果没登录（authentication instanceof AnonymousAuthenticationToken）则抛出异常
            if ("ROLE_LOGIN".equals(needRole)) {
                //  instanceof 的作用是测试它左边的对象是否是它右边的类的实例，返回 boolean 的数据类型
                if (authentication instanceof AnonymousAuthenticationToken) {
                    throw new AccessDeniedException("尚未登录， 请登录！");
                    //--------------------------记一次错误：这个else之前写在第一个if的平级了----------------------------
                } else {
                    //  如果是ROLE_LOGIN直接放行
                    return;
                }
            }
            //  判断用户角色是否为url所需角色
            //  如果用户自带的角色中有一个符合所需对象集合中的一个，那么就能访问请求的Url，如果不能则抛出异常
            //  Collection<? extends GrantedAuthority> authorities的取值在pojo.admin。getAuthorities()里设置
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                if (authority.getAuthority().equals(needRole)) {
                    return;
                }
            }
            //-----------------------------------记一次错误：这个异常抛错地方了----------------------------
            //throw new AccessDeniedException("权限不足， 请联系管理员");
        }
        throw new AccessDeniedException("权限不足， 请联系管理员");
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

